package com.shouke.jmeter.plugin.httpFileUpload.gui;

import com.shouke.jmeter.plugin.httpFileUpload.sampler.BinaryFileUploadSampler;

import com.shouke.jmeter.plugin.httpFileUpload.sampler.HeaderArgument;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.gui.util.HorizontalPanel;
import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
import org.apache.jmeter.testelement.TestElement;
import org.apache.log4j.Logger;

import javax.swing.JTable;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.BorderFactory;
import javax.swing.table.DefaultTableModel;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.util.Vector;
import java.util.Iterator;


public class BinaryFileUploadSamplerGui extends AbstractSamplerGui {
    private JComboBox<String> protocolTypeText;    // 协议类型
    private JComboBox<String> sslTlsText;          // HTTPS SSL/TSL版本
    private JTextField hostText;                   // 服务器名称或IP
    private int textColumns = 5;                   // 用于控制JTextField输入框的最小长度
    private JTextField portText;                   // 端口号
    private JTextField maxConnNumText;             // 连接池支持的最大连接数
    private JTextField maxConnPerRouteText;        // 每个路由最大连接数
    private JTextField getConnTimeoutText;         // 从连接池中获取连接超时时间
    private JTextField connectServerTimeoutText;   // 连接服务器超时时间
    private JTextField waitServerResponseTimeoutText; // 等待服务器返回数据超时时间
    private JTextField urlPathText;                // URL路径
    private JTextField responseEncodingText;       // 服务器返回内容编码
    private JTextField filePathText;               // 文件路径(可以是相对路径，也可以是绝对路径)


    private static Logger logger = org.apache.log4j.Logger.getLogger(BinaryFileUploadSamplerGui.class);
    private DefaultTableModel model;
    private String[] columnNames = {"HEADER", "VALUE"};
    private String[] tmpRow = {"", ""};

    public BinaryFileUploadSamplerGui(){
        init();
        logger.debug("初始化GUI");
    }

    /**
     * 第一步 实现 getLabelResource() 该方法必须返回资源名称，代表组件的标题、名字
     */
    @Override
    public String getLabelResource() {
        logger.debug("请求getLabelResource");
        return this.getClass().getSimpleName();
    }

    /**
     * getStaticLabel 获取Sampler名称，如果缺少该函数，右键线程组->添加->Sampler，会看不到该组件
     */
    @Override
    public String getStaticLabel() {
        logger.debug("请求getStaticLabel");
        return "HTTP BinaryFileUpload Sampler";
    }


    /**
     * 第二步 创建GUI
     */
    public void init() {
        //**************************************************
        // 所有线程共享参数配置
        JPanel allThreadShareSettings = new VerticalPanel();
        allThreadShareSettings.setBorder(BorderFactory.createTitledBorder("所有线程共享参数配置"));
        // 连接数配置面板
        JPanel  connHP =  new HorizontalPanel(5,0.5F);

        // 连接池支持的最大连接数
        JLabel maxConnNumLabel = new JLabel("连接池最大连接数", SwingConstants.RIGHT);
        maxConnNumText = new JTextField(textColumns);
        maxConnNumLabel.setLabelFor(maxConnNumText);
        connHP.add(maxConnNumLabel);
        connHP.add(maxConnNumText);

        // 每个路由支持的最大连接数
        JLabel maxConnPerRouteLabel = new JLabel("   每个路由最大连接数", SwingConstants.RIGHT);
        maxConnPerRouteText = new JTextField(textColumns);
        maxConnPerRouteLabel.setLabelFor(maxConnPerRouteText);
        connHP.add(maxConnPerRouteLabel);
        connHP.add(maxConnPerRouteText);

        allThreadShareSettings.add(connHP);

        // 超时配置面板
        JPanel  timeoutHP =  new HorizontalPanel(5,0.5F);

        // 从连接池中获取连接超时时间（毫秒）
        JLabel getConnTimeoutLabel = new JLabel("从连接池中获取连接超时时间(毫秒)", SwingConstants.RIGHT);
        getConnTimeoutText = new JTextField(textColumns);
        getConnTimeoutLabel.setLabelFor(getConnTimeoutText);
        timeoutHP.add(getConnTimeoutLabel);
        timeoutHP.add(getConnTimeoutText);


        // 连接服务器超时时间（毫秒）
        JLabel connectServerTimeoutLabel = new JLabel("    连接服务器超时时间(毫秒)", SwingConstants.CENTER);
        connectServerTimeoutText = new JTextField(textColumns);
        connectServerTimeoutLabel.setLabelFor(connectServerTimeoutText);
        timeoutHP.add(connectServerTimeoutLabel);
        timeoutHP.add(connectServerTimeoutText);

        // 等待服务器返回数据超时时间（毫秒）
        JLabel waitServerResponseTimeoutLabel = new JLabel("   等待服务器返回数据超时时间(毫秒)", SwingConstants.RIGHT);
        waitServerResponseTimeoutText = new JTextField(textColumns);
        waitServerResponseTimeoutLabel.setLabelFor(waitServerResponseTimeoutText);
        timeoutHP.add(waitServerResponseTimeoutLabel);
        timeoutHP.add(waitServerResponseTimeoutText);

        allThreadShareSettings.add(timeoutHP);

        // web服务器配置组框
        JPanel webServerSettings = new VerticalPanel();
        webServerSettings.setBorder(BorderFactory.createTitledBorder("WEB服务器配置"));

        JPanel webServerSettingsHP = new HorizontalPanel(5,0.5F); // web服务器配置水平面板 //组件之间的横向距离设置为 5

        // 协议类型
        JLabel protocolTypeLabel = new JLabel("协议类型", SwingConstants.RIGHT);
        protocolTypeText = new JComboBox<String>(new String[] {"http", "https"});

        protocolTypeText.setPreferredSize(new Dimension(80, 25)); // 设置ComboBox尺寸
        protocolTypeLabel.setLabelFor(protocolTypeText);

        // 添加到 “web服务器配置水平面板”
        webServerSettingsHP.add(protocolTypeLabel);
        webServerSettingsHP.add(protocolTypeText);

        // HTTPS SSL/TLS
        JLabel sslTlsLabel = new JLabel("    SSL/TLS", SwingConstants.RIGHT);
        sslTlsText = new JComboBox<String>(new String[] {"TLSv1.2", "TLSv1.1", "TLSv1", "TLS", "SSLv3", "SSLv2", "SSL"});

        sslTlsText.setPreferredSize(new Dimension(70, 25)); // 设置ComboBox尺寸
        sslTlsLabel.setLabelFor(sslTlsText);

        webServerSettingsHP.add(sslTlsLabel);
        webServerSettingsHP.add(sslTlsText);


        // 服务器名称或IP
        JLabel hostLabel = new JLabel("     服务器名称或IP", SwingConstants.RIGHT);
        hostText = new JTextField(textColumns);
        hostLabel.setLabelFor(hostText);

        webServerSettingsHP.add(hostLabel);
        webServerSettingsHP.add(hostText);

        // 端口号
        JLabel portLabel = new JLabel("      端口号", SwingConstants.RIGHT);
        portText = new JTextField(textColumns);
        portText.setPreferredSize(new Dimension(30, 0));
        portLabel.setLabelFor(portText);

        webServerSettingsHP.add(portLabel);
        webServerSettingsHP.add(portText, BorderLayout.EAST);
        webServerSettings.add(webServerSettingsHP); // 添加到 web服务器配置组框

        //**************************************************
        // HTTP请求设置组框
        JPanel httpRequestSettings = new VerticalPanel();
        httpRequestSettings.setBorder(BorderFactory.createTitledBorder("HTTP请求设置"));

        // URL路径
        JPanel  urlPathAndEncodingHP =  new HorizontalPanel(5,0.5F);
        JLabel urlPathLabel = new JLabel("URL路径", SwingConstants.RIGHT);
        urlPathText = new JTextField(textColumns);
        urlPathAndEncodingHP.add(urlPathLabel);
        urlPathAndEncodingHP.add(urlPathText);


        // 服务器返回内容编码
        JLabel responseEncodingLabel = new JLabel("    服务器返回内容编码", SwingConstants.RIGHT);
        responseEncodingText = new JTextField(textColumns);
        responseEncodingText.setPreferredSize(new Dimension(150, 0));
        responseEncodingLabel.setLabelFor(responseEncodingText);
        urlPathAndEncodingHP.add(responseEncodingLabel);
        urlPathAndEncodingHP.add(responseEncodingText, BorderLayout.EAST);



        httpRequestSettings.add(urlPathAndEncodingHP);

        // 文件名\路径
        JPanel  filePathHP =  new HorizontalPanel(5,0.5F);
        JLabel filePathLabel = new JLabel("文件路径：", SwingConstants.RIGHT);
        filePathText = new JTextField(textColumns);
        filePathHP.add(filePathLabel);
        filePathHP.add(filePathText);
        httpRequestSettings.add(filePathHP);

        //**************************************************
        // 请求头设置组框
        JPanel headersSettings = new VerticalPanel();
        headersSettings.setBorder(BorderFactory.createTitledBorder("请求头设置"));

        // 表格参数面板
        JPanel tablePanel = new HorizontalPanel();

        model = new DefaultTableModel();
        model.setDataVector(null, columnNames); // 设置表头名称
        final JTable table = new JTable(model);
        table.setRowHeight(30); // 设置行高
        table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); // 失去光标退出编辑


        //表格滚动条
        JScrollPane scrollpane = new JScrollPane(table){
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(0, 300); // 设置滚动条大小，以增加表格展示面积
            }
        };


        tablePanel.add(scrollpane);
        headersSettings.add(tablePanel);

        JPanel btnPanel = new HorizontalPanel();
        btnPanel.setLayout(new FlowLayout()); //流式布局
        // 添加按钮
        JButton addBtn = new JButton("增加");
        addBtn.addActionListener(new ActionListener() {
           @Override
           public  void actionPerformed(ActionEvent arg0) { model.addRow(tmpRow);}
        });

        // 删除按钮
        JButton delBtn = new JButton("删除");
        delBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                int rowIndex = table.getSelectedRow();
                if(rowIndex != -1) {
                    model.removeRow(rowIndex);
                } else {
                    int rows = table.getRowCount();
                    if (rows >= 1) {
                        rowIndex = rows - 1;
                        model.removeRow(rowIndex);
                    }
                }
            }
        });

        btnPanel.add(delBtn, FlowLayout.CENTER);
        btnPanel.add(addBtn, FlowLayout.CENTER);
        headersSettings.add(btnPanel);
        httpRequestSettings.add(headersSettings);


        //设置总panel，垂直布局
        JPanel settingPanel = new VerticalPanel();
        settingPanel.setBorder(makeBorder());
        settingPanel.add(makeTitlePanel());

        settingPanel.add(allThreadShareSettings);
        settingPanel.add(webServerSettings);
        settingPanel.add(httpRequestSettings);

        //全局布局设置
        setLayout(new BorderLayout(0, 5));
        setBorder(makeBorder());
        add(settingPanel, BorderLayout.CENTER);
    }


    // 转换 Vector<Vector<String>>  为Vector<HeaderArgument>
    private Vector<HeaderArgument> parseHeaderArguments1(Vector<Vector<String>> methodArgs) {
        Vector<HeaderArgument> headerArguments = new Vector<>();
        if (!methodArgs.isEmpty()) {
            //处理参数
            Iterator<Vector<String>> it = methodArgs.iterator();
            while(it.hasNext()) {
                Vector<String> methodArgument = it.next();
                if (!methodArgument.isEmpty()) {
                    headerArguments.add(new HeaderArgument(methodArgument.get(0), methodArgument.get(1)));
                }
            }
        }
        return headerArguments;
    }

    // 转换 Vector<HeaderArgument>  为  Vector<Vector<String>>
    private Vector<Vector<String>> parseHeaderArguments2(Vector<HeaderArgument> methodArgs) {
        Vector<Vector<String>> methodArguments = new Vector<>();
        if (!methodArgs.isEmpty()) {
            //处理参数
            Iterator<HeaderArgument> it = methodArgs.iterator();
            while(it.hasNext()) {
                HeaderArgument headerArgument = it.next();
                if (headerArgument != null) {
                    Vector<String> vector = new Vector<>();
                    vector.add(headerArgument.getHeaderName());
                    vector.add(headerArgument.getHeaderValue());
                    methodArguments.add(vector);
                }
            }
        }
        return methodArguments;
    }


    /**
     * 第三步 实现 public void configure(TestElement el) //Use this method to set data into your GUI elements
     */
    @Override
    public void configure(TestElement element) {
        super.configure(element); // 必不可少

        logger.debug("获取Sampler对象属性值赋值给GUI");
        BinaryFileUploadSampler sampler = (BinaryFileUploadSampler) element;
        maxConnNumText.setText(sampler.getMaxConnNum());
        maxConnPerRouteText.setText(sampler.getMaxConnPerRoute());
        getConnTimeoutText.setText(sampler.getGetConnTimeout());
        connectServerTimeoutText.setText(sampler.getConnectServerTimeout());
        waitServerResponseTimeoutText.setText(sampler.getWaitServerResponseTimeout());

        protocolTypeText.setSelectedItem(sampler.getProtocolType());
        sslTlsText.setSelectedItem(sampler.getSslTls());
        hostText.setText(sampler.getHost());
        portText.setText(sampler.getPort());

        urlPathText.setText(sampler.getUrlPath());
        responseEncodingText.setText(sampler.getResponseEncoding());
        filePathText.setText(sampler.getFilePath());

        // 设置表格数据
        Vector<String> columnNames = new Vector<String>();
        columnNames.add("header");
        columnNames.add("value");
        model.setDataVector(parseHeaderArguments2(sampler.getHeaderArguments()), columnNames);
    }


    /**
     * 第四步 实现 public void modifyTestElement(TestElement e)
     */
    @Override
    public void modifyTestElement(TestElement te) {
        te.clear();
        configureTestElement(te); // 调用该方法提供一些默认数据
        logger.debug("把GUI数据赋值给sampler");
        BinaryFileUploadSampler sampler = (BinaryFileUploadSampler) te;
        sampler.setMaxConnNum(maxConnNumText.getText());
        sampler.setMaxConnPerRoute(maxConnPerRouteText.getText());

        sampler.setGetConnTimeout(getConnTimeoutText.getText());
        sampler.setConnectServerTimeout(connectServerTimeoutText.getText());
        sampler.setWaitServerResponseTimeout(waitServerResponseTimeoutText.getText());

        sampler.setProtocolType(protocolTypeText.getSelectedItem().toString());
        sampler.setSslTls(sslTlsText.getSelectedItem().toString());
        sampler.setHost(hostText.getText());
        sampler.setPort(portText.getText());

        sampler.setUrlPath(urlPathText.getText());
        sampler.setResponseEncoding(responseEncodingText.getText());
        sampler.setFilePath(filePathText.getText());


        sampler.setHeaderArguments(parseHeaderArguments1(model.getDataVector()));

    }

    /**
     * 第五步 实现 public TestElement createTestElement() // 该方法应该创建一个TestElement 类实例
     * 然后把该实例传递给上述创建的 modifyTestElement(TestElement) 方法
     */
    @Override
    public TestElement createTestElement() {
        logger.debug("创建Sampler对象");
        BinaryFileUploadSampler sampler = new BinaryFileUploadSampler();
        modifyTestElement(sampler);
        return sampler;
    }

    @Override
    public void clearGui() {
        super.clearGui();
        logger.debug("清空GUI数据");
        maxConnNumText.setText("20000"); // 界面初始值为 20000
        maxConnPerRouteText.setText("20000");
        getConnTimeoutText.setText("120000");
        connectServerTimeoutText.setText("60000");
        waitServerResponseTimeoutText.setText("60000");

        protocolTypeText.setSelectedIndex(0);
        sslTlsText.setSelectedIndex(0);
        hostText.setText("");
        portText.setText("80");

        urlPathText.setText("");
        responseEncodingText.setText("utf-8");
        filePathText.setText("");
        model.setDataVector(null, columnNames);
    }
}